# coding: utf-8

import json
import time
import datetime
import logging

from flask import request, render_template, current_app
from geventwebsocket import WebSocketError

from .. import db
from app.ccws.models import create_outbound_mission
from . import cchtml_bp, ccws_bp
from .constant import CallState, QueueState
from .models import OutBoundRecord


@cchtml_bp.route('/')
def index():
    """
    websocket的html页面测试
    """
    return render_template('message.html')


@cchtml_bp.route('/make_call')
def make_call():
    """
    座席通过ws外呼电话
    """
    if not current_app.observers:
        return 'websocket未连接，请通知管理员处理!'

    # 发送待呼叫事件
    mobile = request.args.get("mobile", None)
    if not mobile:
        return '呼叫号码未填写!'

    call_id = str(int(time.time())) + mobile
    message = '{"msgType":"CCX_Call", "id":"%s", "called":"%s"}' % (
        call_id, mobile,)
    key_list = list(current_app.observers.keys())
    # print('*' * 50)
    # print(message)
    # print(key_list)
    # print('*' * 50)
    for key in key_list:
        socket = current_app.observers.get(key)
        if not socket.closed:
            try:
                socket.send(message)
            except WebSocketError:
                del current_app.observers[key]
                print(socket, 'has errors')
        else:
            del current_app.observers[key]
            print(socket, 'is closed')

    # 返回外呼中的提示信息
    return '{mobile}已加入待呼叫队列中'.format(mobile=mobile)


@ccws_bp.route('/message/')
def message(socket):
    """
    建立websocket连接，并等待接受信息
    """
    obj_id = str(id(socket))
    current_app.observers[obj_id] = socket

    while not socket.closed:
        message = socket.receive()
        logging.error('*' * 50)
        logging.error('message receive:')
        logging.error(message)
        logging.error('*' * 50)

        # 接收到呼叫结果的后续处理
        try:
            message_json = json.loads(message)
        except Exception as e:
            logging.error('!' * 50)
            logging.error(e)
            logging.error('!' * 50)
            message_json = {}
        if not isinstance(message_json, dict):
            message_json = {}
        if 'state' in message_json:
            # 更新 outbound_dict 中的 call_state
            local_call_id = message_json['id']
            tmp_outbound_record = OutBoundRecord.query.filter_by(
                local_call_id=local_call_id
            ).first()
            if local_call_id in current_app.outbound_dict:
                current_app.outbound_dict[local_call_id]['call_state'] = message_json['state']

            # 通话结束的情况等异常情况
            if message_json['state'] in [
                CallState.CALLOVER.value,
                CallState.BUSY.value,
                CallState.INVALID_CALL.value,
                CallState.TIMEOUT.value,
                CallState.INVALID_NUMBER.value,
                CallState.NO_BACK_TONE.value,
                CallState.OTHER_ERROR.value,
                CallState.CANCLE_CALL.value,
            ]:
                logging.error('!' * 25 + '#' * 25)
                logging.error(current_app.outbound_dict)
                logging.error('!' * 25 + '#' * 25)

                if local_call_id in current_app.outbound_dict:
                    del current_app.outbound_dict[local_call_id]
                tmp_outbound_record.queue_state = QueueState.DONE.value
                tmp_outbound_record.call_state = message_json['state']

                logging.error(current_app.outbound_dict)
                logging.error('!' * 25 + '#' * 25)
                db.session.flush()

            # add by zhouhl 2017-09-21
            # 增加处理外呼接通就挂断的客户，重新写入外呼任务
            # NOTE 记录中没有admin_id信息的，说明还没转到坐席上
            if message_json['state'] == CallState.CALLOVER.value \
                and not tmp_outbound_record.admin_id:
                tmp_mobile = tmp_outbound_record.mobile
                fail_called_count = OutBoundRecord.query.filter(
                    OutBoundRecord.mobile == tmp_mobile,
                    OutBoundRecord.call_state.in_(
                        [CallState.CALLOVER.value, ]
                    ),
                    OutBoundRecord.schedule_time > datetime.date.today(),
                    OutBoundRecord.admin_id == '',
                ).count()

                next_schedule_time = datetime.datetime.now()
                if fail_called_count == 1:
                    # 延迟3分钟
                    call_delta = datetime.timedelta(seconds = 60 * 3)
                elif fail_called_count == 2:
                    # 延迟6分钟
                    call_delta = datetime.timedelta(seconds = 60 * 6)
                else:
                    # 延迟10分钟
                    call_delta = datetime.timedelta(seconds = 60 * 10)

                if fail_called_count <= 3:
                    # 失败三次以内才重复添加外呼任务
                    tmp_outbound_record, err = create_outbound_mission(
                        mobile=tmp_mobile,
                        call_reason=tmp_outbound_record.call_reason,
                        schedule_time=next_schedule_time + call_delta,
                        try_again=True,
                        user_id=tmp_outbound_record.user_id
                    )
                    if tmp_outbound_record:
                        db.session.add(tmp_outbound_record)

            # 被叫忙于超时无应答，重新写入外呼任务
            if message_json['state'] in [
                CallState.BUSY.value,
                CallState.TIMEOUT.value,
            ]:
                tmp_mobile = tmp_outbound_record.mobile
                fail_called_count = OutBoundRecord.query.filter(
                    OutBoundRecord.mobile == tmp_mobile,
                    OutBoundRecord.call_state.in_(
                        [CallState.BUSY.value, CallState.TIMEOUT.value]
                    ),
                    OutBoundRecord.schedule_time > datetime.date.today(),
                ).count()

                next_schedule_time = datetime.datetime.now()
                if fail_called_count == 1:
                    # 延迟3分钟
                    call_delta = datetime.timedelta(seconds = 60 * 3)
                elif fail_called_count == 2:
                    # 延迟6分钟
                    call_delta = datetime.timedelta(seconds = 60 * 6)
                elif fail_called_count == 3:
                    # 延迟10分钟
                    call_delta = datetime.timedelta(seconds = 60 * 10)
                elif fail_called_count == 4:
                    # 延迟30分钟
                    call_delta = datetime.timedelta(seconds = 60 * 30)
                elif fail_called_count == 5:
                    # 延迟60分钟
                    call_delta = datetime.timedelta(seconds = 60 * 60)
                else:
                    # 延迟120分钟
                    call_delta = datetime.timedelta(seconds = 60 * 60 * 2)

                if fail_called_count <= 6:
                    # 失败六次以内才重复添加外呼任务
                    tmp_outbound_record, err = create_outbound_mission(
                        mobile=tmp_mobile,
                        # call_reason = CallReason.TRY_AGAIN.value,
                        call_reason=tmp_outbound_record.call_reason,
                        schedule_time=next_schedule_time + call_delta,
                        try_again=True,
                        user_id=tmp_outbound_record.user_id
                    )
                    if tmp_outbound_record:
                        db.session.add(tmp_outbound_record)

            # 记录明城callID
            if message_json['state'] == CallState.DIALING.value:
                tmp_outbound_record.call_id = message_json['callId']
                tmp_outbound_record.call_time = datetime.datetime.now()

            # 更新录音地址
            # NOTE 在内网服务器上运行定时任务， 上传相关录音
            if message_json['state'] == CallState.RECORDFILE.value:
                tmp_outbound_record.audio_path = message_json['recordFile']

            # 记录接听座席ID
            if message_json['state'] == CallState.TALKING.value:
                tmp_outbound_record.agent_id = message_json['agentId']

            # 提交数据
            db.session.commit()


